#include "../common/dipatcher.hpp"
#include "rpc_caller.hpp"
#include "requestor.hpp"
#include "rpc_registry.hpp"
#include"rpc_topic.hpp"

namespace rpc
{
    namespace client
    {
        // 注册服务客户端:应用于服务客户端向注册中心进行注册服务
        class RegistryClient
        {
        public:
            using ptr = std::shared_ptr<RegistryClient>;
            RegistryClient(const std::string &ip, int host)
                : _requestor(std::make_shared<Requestor>()),
                  _provider(std::make_shared<Provider>(_requestor)),
                  _dispacher(std::make_shared<dipatcher>())
            {
                auto cb_rsp = std::bind(&rpc::client::Requestor::onResponse, _requestor.get(), std::placeholders::_1, std::placeholders::_2);
                _dispacher->rigisteHandler<BaseMessage>(rpc::MY_TYPE::RSP_SERVICE, cb_rsp);
                auto cb = std::bind(&rpc::dipatcher::onMessage, _dispacher.get(), std::placeholders::_1, std::placeholders::_2);
                _client = rpc::ClientFactory::create(ip, host);
                _client->setMessageCallback(cb);
                _client->connect();
            }
            // 向外提供服务注册接口
            bool registryMethod(const std::string &method, Address &host)
            {
                delog("procide开始注册方法");
                return _provider->onRegistry(_client->connection(), method, host);
            }

        private:
            Requestor::ptr _requestor;
            client::Provider::ptr _provider;
            dipatcher::ptr _dispacher;
            BaseClient::ptr _client; // 使用工厂接口开创建的对象，在构造函数里面进行创建
        };

        class DiscoverClient
        {
        public:
            using ptr = std::shared_ptr<DiscoverClient>;
            DiscoverClient(const std::string &ip, int host, const Discover::offlineCallback &offlinecb)
                : _requestor(std::make_shared<Requestor>()),
                  _discover(std::make_shared<Discover>(_requestor, offlinecb)),
                  _dispacher(std::make_shared<dipatcher>())
            {
                auto cb_rsp = std::bind(&rpc::client::Requestor::onResponse, _requestor.get(), std::placeholders::_1, std::placeholders::_2);
                _dispacher->rigisteHandler<BaseMessage>(rpc::MY_TYPE::RSP_SERVICE, cb_rsp);
                auto req_cb = std::bind(&Discover::onRequestor, _discover.get(), std::placeholders::_1, std::placeholders::_2);
                _dispacher->rigisteHandler<rpc::ServerRequest>(MY_TYPE::REQ_SERVICE, req_cb);
                _client = rpc::ClientFactory::create(ip, host);
                auto cb = std::bind(&rpc::dipatcher::onMessage, _dispacher.get(), std::placeholders::_1, std::placeholders::_2);
                _client->setMessageCallback(cb);
                _client->connect();
            }
            // 向外提供发现服务接口
            bool serviceDiscovery(const std::string &method, Address &host)
            {
                delog(" serviceDiscovery开始");
                bool ret =  _discover->serviceDiscovery(_client->connection(), method, host);
                delog(" serviceDiscovery结束");
                return ret;
            }

        private:
            Requestor::ptr _requestor;
            client::Discover::ptr _discover;
            dipatcher::ptr _dispacher;
            BaseClient::ptr _client;
        };

        class RpcClient
        {
        public:
            using ptr = std::shared_ptr<RpcClient>;
            // bool值表示是否启用服务发现，若启用就在discover里面找，若不启用就直接实例化
            RpcClient(bool enableDiscover, const std::string &ip, int port)
                : _requestor(std::make_shared<Requestor>()),
                  _enable(enableDiscover),
                  _caller(std::make_shared<rpc::client::RpcCaller>(_requestor)),
                  _dispacher(std::make_shared<dipatcher>())
            {
                // 针对rpc请求后的rsp响应
                auto cb_rsp = std::bind(&rpc::client::Requestor::onResponse, _requestor.get(),
                                        std::placeholders::_1, std::placeholders::_2);
                _dispacher->rigisteHandler<BaseMessage>(MY_TYPE::RSP_RPC, cb_rsp);

                // 根据是否启用发现服务来进行实例化discover
                if (_enable)
                {
                    // 如果启用服务发现功能，那服务就是传进来的地址信息
                    // 将删除函数设置进discover中
                    auto cb = std::bind(&RpcClient::delClient, this, std::placeholders::_1);
                    _discover = std::make_shared<DiscoverClient>(ip, port, cb);
                }
                else
                {
                    // 如果没有启用那就直接实例化号_client
                    auto cb = std::bind(&rpc::dipatcher::onMessage, _dispacher.get(), std::placeholders::_1, std::placeholders::_2);
                    _client = rpc::ClientFactory::create(ip, port);
                    _client->setMessageCallback(cb);
                    _client->connect();
                }
            }
            // 回调函数
            bool call(const std::string &method, Json::Value &params, Json::Value &result)
            {
                delog("开始获取客户端");
               
                auto client = getClient(method);
                delog("获取客户端成功");
                if (client.get() == nullptr)
                {
                    return false;
                }
                delog("开始_caller->call");
                return _caller->call(client->connection(), method, params, result);
            }
            bool call(const std::string &method, Json::Value &params, RpcCaller::JsonAsync &result)
            {
                auto client = getClient(method);
                
                if (client.get() == nullptr)
                {
                    return false;
                }
                bool ret =  _caller->call(client->connection(), method, params, result);
                return ret;
            }
            bool call(const std::string &method, Json::Value &params, const RpcCaller::JsonCallback &result)
            {
                auto client = getClient(method);
                
                if (client.get() == nullptr)
                {
                    return false;
                }
                return _caller->call(client->connection(), method, params, result);
            }

        private:
            BaseClient::ptr newClient(const Address& host)
            {
                auto cb = std::bind(&rpc::dipatcher::onMessage, _dispacher.get(), std::placeholders::_1, std::placeholders::_2);
                delog("host:%s:%d",host.first.c_str(), host.second)
                auto _client = rpc::ClientFactory::create(host.first, host.second);
                _client->setMessageCallback(cb);
                _client->connect();
                addClient(host, _client);
                return _client;
            }

            BaseClient::ptr getClient(const Address& addr)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _clients_pool.find(addr);
                if (it == _clients_pool.end())
                {
                    return BaseClient::ptr();
                }
                return it->second;
            }

            BaseClient::ptr getClient(std::string method)
            {
                BaseClient::ptr client;
                // 如果是服务发现启动了，通过服务发现获取服务地址信息
                delog("getClient开始获取客户端");
                if (_enable)
                {
                    delog("getClient开启服务发现获取客户端");
                    Address host;
                    auto ret = _discover->serviceDiscovery(method, host);
                    if (ret == false)
                    {
                        errlog("%s服务发现失败", method.c_str());
                        return BaseClient::ptr();
                    }
                    // 根据host在连接池里面获取连接
                    auto rpc_client = getClient(host);
                    if (rpc_client.get() == nullptr)
                    {
                        // 连接池内没有，那就自己创建
                        delog("%s:%d", host.first.c_str(), host.second);
                        client = newClient(host);
                    }
                    else
                    {
                        client = rpc_client;
                    }
                        delog("getClient开启服务发现获取客户端成功");
                }
                else
                {
                    client = _client;
                }

                return client;
            }

            void addClient(Address host, const BaseClient::ptr &client)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _clients_pool.insert(std::make_pair(host, client));
            }

            void delClient(Address host)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _clients_pool.erase(host);
            }

        private:
            struct AddressHash
            {
                size_t operator()(const Address &host) const
                {
                    std::string addr = host.first + std::to_string(host.second);
                    return std::hash<std::string>{}(addr);
                }
            };
            std::mutex _mutex;
            bool _enable;
            Requestor::ptr _requestor;
            dipatcher::ptr _dispacher;
            RpcCaller::ptr _caller;
            client::DiscoverClient::ptr _discover;
            BaseClient::ptr _client;
            std::unordered_map<Address, BaseClient::ptr, AddressHash> _clients_pool; // 连接池，发现后的
        };

        class TopicClient
        {
          public:
              using ptr = std::shared_ptr<TopicClient>;
             TopicClient(const std::string &ip, int host)
                  : _requestor(std::make_shared<Requestor>()),
                   _topic_manager(std::make_shared<TopicManager>(_requestor)),
                    _dispacher(std::make_shared<dipatcher>())
              {
                  auto cb_rsp = std::bind(&rpc::client::Requestor::onResponse, _requestor.get(), std::placeholders::_1, std::placeholders::_2);
                  _dispacher->rigisteHandler<BaseMessage>(rpc::MY_TYPE::RSP_TOPIC, cb_rsp);
                  
                  auto req_cb = std::bind(&TopicManager::onPublish, _topic_manager.get(), std::placeholders::_1, std::placeholders::_2);
                  _dispacher->rigisteHandler<rpc::TopicRequest>(MY_TYPE::RSP_TOPIC, req_cb);

                  _client = rpc::ClientFactory::create(ip, host);
                  auto cb = std::bind(&rpc::dipatcher::onMessage, _dispacher.get(), std::placeholders::_1, std::placeholders::_2);
                  _client->setMessageCallback(cb);
                  _client->connect();
              }

              // 创建主题
              bool create( const std::string &key)
              {
                  return _topic_manager->create(_client->connection(), key);
              }
              // 删除主题
              bool remove(const BaseConnection::ptr &conn, const std::string &key)
              {
                  return _topic_manager->remove(_client->connection(), key);
              }

              // 订阅主题:订阅主题后要设置函数来进行处理
              bool subscribe( const std::string &key, const TopicManager::SubCallback &cb)
              {
                  return _topic_manager->subscribe(_client->connection(), key, cb);
              }
              // 取消订阅
              bool cancel(  const std::string &key)
              {
                  return _topic_manager->cancel(_client->connection(), key);
              }

              // 发布主题
              bool publish(  const std::string &key, const std::string &msg)
              {
                  return _topic_manager->publish(_client->connection(), key, msg);
              }
              // 提供给dispacher模块的操作函数
              void onPublish( const TopicRequest::ptr &msg)
              {

                  _topic_manager->onPublish(_client->connection(), msg);
              }

              //断开连接
              void shutdown()
              {
                  _client->shutdown();
              }

          private:
              Requestor::ptr _requestor;
              dipatcher::ptr _dispacher;
              TopicManager::ptr _topic_manager;
              BaseClient::ptr _client;
        };
    }
}